/* 
 * This trigger updates the total price of a quote when a related quote line
 * item changes.
 */
trigger quoteLineTrigger on quoteLine__c(before insert, before update, after insert, after update, after delete) {
	/* Trigger context variables like Trigger.isBefore and Trigger.isUpdate
	   allow a multicondition trigger to execute Apex Code only when a
	   certain condition occurs. */
	if (Trigger.isBefore) {
		for (quoteLine__c ql : Trigger.new) {
			/* If the trigger fires before quote line items are updated or
			   inserted, the TotalPrice__c field is updated on each item.
			   Note that this calculation could have also been implemented
			   with a formula field in the application. */
			if (Trigger.isUpdate || Trigger.isInsert) {
				ql.totalprice__c = ql.unitprice__c * ql.quantity__c;
			} 
		}
	} else {
		/* As we did in Example 1, use a set to make sure we have a list of all
		   the distinct quotes that we are modifying. This is the first step in a
		   common bulk processing idiom. */
		Set<Id> quoteIds = new Set<Id>();
		
		/* Note the use of the ternary operator to get the correct size of the
		   lists and then the correct IDs for each quote--for the delete case,
		   the application uses the Trigger.old list variable, while for insert
		   and update, the application uses Trigger.new. */
		for (Integer i = 0; i < (Trigger.isDelete ? Trigger.old.size() : Trigger.new.size()); i++) {
			quoteIds.add(Trigger.isDelete ? Trigger.old[i].quote__c : Trigger.new[i].quote__c);
		}
		
		/* Now as the second step in our bulk processing idiom, use the set to issue
		   a SOQL query and create a map of Ids to Quotes */
		Map<Id, Quote__c> quotes = new Map<Id, Quote__c>([select id, total__c from quote__c where id in :quoteIds]);
		
		// For each quote line item in Trigger.old or Trigger.new, find the quoteId
		for (Integer i = 0; i < (Trigger.isDelete ? Trigger.old.size() : Trigger.new.size()); i++) {
			String quoteId = Trigger.isDelete ? Trigger.old[i].quote__c : Trigger.new[i].quote__c;
			
			/* If the trigger fires after a quote line item is updated or deleted
			   the total__c field on the parent quote needs to be updated. However,
			   if this trigger fires in the middle of inserting a quote (that is, if
			   we're working on the same quote that the util.copyLineItemsFromOpp
			   method is working on, we skip this logic here (see Example 2) */
			if(util.inQuoteTrigger) continue;
			
			/* As the third step in our bulk processing idiom, get the parent quote
			   (which must be in the set we created above) */
			quote__c q = quotes.get(quoteId);
			
			/* If the quote total does not yet have a value, the trigger first sets
			   it to zero.*/
			if (q.total__c == null) q.total__c = 0;
			
			/* If the quote line item is being inserted, the trigger
			   increments the total value of the quote */
			if (Trigger.isInsert && Trigger.new[i].totalprice__c != null) {
				q.total__c += Trigger.new[i].totalprice__c;
			}
			
			/* If the quote line item is being updated, the trigger adds the new
			   line item total to the quote, and subtracts the old line item
			   total from the quote */
			if (Trigger.isUpdate) {
				if (Trigger.new[i].totalprice__c != null)
					q.total__c += Trigger.new[i].totalprice__c;
				if (Trigger.old[i].totalprice__c != null)
					q.total__c -= Trigger.old[i].totalprice__c;
			}
			
			/* If the quote line item is being deleted, the trigger
			   decrements the total value of the quote */
			if (Trigger.isDelete && Trigger.old[i].totalprice__c != null) {
				q.total__c -= Trigger.old[i].totalprice__c;
			}
		}
		
		/* For the fourth and final step of the bulk processing idiom,
		   update all quotes in bulk */
		update quotes.values();
	}
}